package com.xiaoshuidi.cloud.module.finance.job.withdraw;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.pay.config.PayProperties;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayClient;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayClientFactory;
import com.xiaoshuidi.cloud.framework.pay.core.client.PayCommonResult;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.QueryBalanceReqDTO;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.QueryBalanceRespDTO;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.WithdrawApplyReqDTO;
import com.xiaoshuidi.cloud.framework.pay.core.client.impl.tongshangyun.dto.WithdrawApplyRespDTO;
import com.xiaoshuidi.cloud.framework.redis.sequence.TimebaseSequenceGenerator;
import com.xiaoshuidi.cloud.framework.tenant.core.job.TenantJob;
import com.xiaoshuidi.cloud.framework.tenant.core.util.TenantUtils;
import com.xiaoshuidi.cloud.module.finance.controller.admin.merchant.vo.merchant.PayMerchantRespVO;
import com.xiaoshuidi.cloud.module.finance.convert.finance.TongLianConvert;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.collection.FinanceCollectionConfigDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.finance.FinanceThirdWithdrawDO;
import com.xiaoshuidi.cloud.module.finance.dal.dataobject.merchant.PayMerchantDO;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.collection.FinanceCollectionConfigMapper;
import com.xiaoshuidi.cloud.module.finance.dal.mysql.finance.FinanceThirdWithdrawMapper;
import com.xiaoshuidi.cloud.module.finance.enums.finance.PayChannelTypeEnum;
import com.xiaoshuidi.cloud.module.finance.enums.withdraw.TongLianRefundStatusEnum;
import com.xiaoshuidi.cloud.module.finance.enums.withdraw.WithdrawStatusEnum;
import com.xiaoshuidi.cloud.module.finance.job.withdraw.dto.TongLianWithdrawDTO;
import com.xiaoshuidi.cloud.module.finance.service.merchant.PayMerchantService;
import com.xiaoshuidi.cloud.module.finance.util.HttpConnectionUtil;
import com.xiaoshuidi.cloud.module.finance.util.SybUtil;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * 提现
 */
@Slf4j
@TenantJob
@Component("thirdWithdrawJob")
public class ThirdWithdrawJob {
    @Resource
    private PayMerchantService merchantService;

    @Resource
    private PayClientFactory payClientFactory;
    @Resource
    private PayProperties payProperties;

    @Resource
    private TimebaseSequenceGenerator timebaseSequenceGenerator;

    @Resource
    private FinanceThirdWithdrawMapper financeThirdWithdrawMapper;

    @Resource
    private FinanceCollectionConfigMapper financeCollectionConfigMapper;

    @Async
    @XxlJob("thirdWithdrawJob")
    public void execute() throws Exception {
        try {
            log.info("通商云提现任务开始");
            //查询商户表
            List<PayMerchantDO> merChantList = merchantService.getAllMerchantList();
            log.info("提现商户的个数{}", merChantList.size());
            if (!CollectionUtils.isEmpty(merChantList)) {
                PayClient client = payClientFactory.getPayClient(payProperties.getChannelId());
                for (PayMerchantDO payMerchantDO : merChantList) {
                    //查询单个商户的
                    PayCommonResult<QueryBalanceRespDTO> queryBalance = null;
                    try {
                        QueryBalanceReqDTO reqDTO = new QueryBalanceReqDTO()
                                .setBizUserId(payMerchantDO.getId().toString());
                        log.info("{}通商云查询余额入参{}", payMerchantDO.getName(), JsonUtils.toJsonString(reqDTO));
                        queryBalance = client.queryBalance(reqDTO);
                    } catch (Exception e) {
                        log.error("通商云查询账户余额发生异常：{}", e.getMessage());
                    }
                    if (queryBalance.isSuccess()) {
                        QueryBalanceRespDTO data = queryBalance.getData();
                        //todo
                          Long availableAmount = data.getAllAmount()-data.getFreezenAmount();
//                        Long availableAmount = 301700L;
                        log.info("{}通商云查询余额返回参数:{}", payMerchantDO.getName(), JsonUtils.toJsonString(data));
                        //发起提现
                        String txNo = "TX".concat(timebaseSequenceGenerator.YYYYMMDDHHMMSS.next("TX"));
                        LocalDateTime now = LocalDateTime.now();
                        TenantUtils.execute(payMerchantDO.getTenantId(), () -> {
                            //插入本地提现表
                            FinanceThirdWithdrawDO financeThirdWithdrawDO = new FinanceThirdWithdrawDO()
                                    .setThirdId(payMerchantDO.getThirdId())
                                    .setWithdrawNo(txNo)
                                    .setWithdrawTime(now)
                                    .setAccountNo(payMerchantDO.getNo())
                                    .setAccountId(payMerchantDO.getId())
                                    .setApartmentId(payMerchantDO.getApartmentId())
                                    .setAccountName(payMerchantDO.getName())
                                    .setBalance(availableAmount)
                                    .setAccType(payMerchantDO.getAccType())
                                    .setBankNo(payMerchantDO.getBankCardNo())
                                    .setStatus(WithdrawStatusEnum.PROCESS.getName());
                            financeThirdWithdrawMapper.insert(financeThirdWithdrawDO);
                        });
                        String expireDateTime = now.plusMinutes(10).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        WithdrawApplyReqDTO applyReqDTO = new WithdrawApplyReqDTO()
                                .setBizUserId(payMerchantDO.getId().toString())
                                .setAmount(availableAmount)
                                //todo 提现费率 目前写0
                                .setFee(0L)
                                .setBankCardNo(payMerchantDO.getBankCardNo())
                                .setBankCardPro(Long.valueOf(payMerchantDO.getAccType()))
                                .setBackUrl(getChannelWithdrawNotifyUrl())
                                .setBizOrderNo(txNo)
                                .setOrderExpireDatetime(expireDateTime)
                                .setSummary(payMerchantDO.getName() + "提现" + availableAmount);
                        try {
                            log.info("{}通商云提现入参{}", payMerchantDO.getName(), JsonUtils.toJsonString(applyReqDTO));
                            PayCommonResult<WithdrawApplyRespDTO> result = client.withdrawApply(applyReqDTO);
                            if (result.isSuccess()) {
                                WithdrawApplyRespDTO resultData = result.getData();
                                log.info("{}通商云提现返回参数:{}", payMerchantDO.getName(), JsonUtils.toJsonString(resultData));
                                //修改状态
                                financeThirdWithdrawMapper.updateStatusByTXNo(resultData.getBizOrderNo(), WithdrawStatusEnum.PROCESS.getName(),
                                        FinanceThirdWithdrawDO.builder()
                                                .thirdWithdrawNo(resultData.getOrderNo())
                                                .build());
                            } else {
                                financeThirdWithdrawMapper.updateStatusByTXNo(txNo, WithdrawStatusEnum.PROCESS.getName(),
                                        FinanceThirdWithdrawDO.builder()
                                                .status(WithdrawStatusEnum.FAILURE.getName())
                                                .reason(result.getMsg())
                                                .build());

                            }
                        } catch (Exception e) {
                            log.error("通商云提现生异常：{}", e.getMessage());
                        }
                    }
                }
            }
        } catch (ServiceException e) {
            log.info("通商云提现任务异常", e);
            XxlJobHelper.handleFail("通商云提现任务失败, " + e.getMessage());
        }
    }

    private String getChannelWithdrawNotifyUrl() {
        return payProperties.getTongshangyunNotifyUrl() + "/" + payProperties.getChannelId();
    }


    @Async
    @XxlJob("tongLianWithdrawJob")
    public void tongLianExecute() {
        String params = XxlJobHelper.getJobParam();
        LocalDate localDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 将 LocalDate 转换为字符串
        String startDateStr = localDate.format(formatter);
        List<String> dateList = new ArrayList();
        String endDateStr = "";
        if(StringUtils.isNotBlank(params)){
            try {
                String[] split = params.split("-");
                if (split.length > 1){
                    startDateStr = split[0];
                    endDateStr = split[1];
                    LocalDate startDate = LocalDate.parse(startDateStr, formatter);
                    LocalDate endDate = LocalDate.parse(endDateStr, formatter);
                    dateList = getDatesBetween(startDate, endDate);
                }
            } catch (Exception e) {
                log.error("参数转换异常，入参：{}", params);
                throw new RuntimeException(e);
            }
        }else {
            dateList.add(startDateStr);
        }

        List<TongLianWithdrawDTO> tonglianList = new ArrayList<>();
        for (String dateStr : dateList) {
            try {
                List<TongLianWithdrawDTO> settrxList = getSettrxList(dateStr);
                if (CollectionUtils.isNotEmpty(settrxList)){
                    tonglianList.addAll(settrxList);
                }
            } catch (Exception e) {
                log.error("通联查询结算单失败", e);
            }
        }

        List<FinanceThirdWithdrawDO> withdrawList =
                tonglianList.stream()
                        .map(l -> TongLianConvert.INSTANCE.convert(l))
                        .collect(Collectors.toList());
        withdrawList.stream().forEach(l -> {
            l.setWithdrawNo("TX".concat(timebaseSequenceGenerator.YYYYMMDDHHMMSS.next("TX")));
            // 处理状态
            l.setStatus(TongLianRefundStatusEnum.getName(l.getStatus()));
        });
        financeThirdWithdrawMapper.insertBatch(withdrawList);
    }




    public List<String> getDatesBetween(LocalDate start, LocalDate end) {
        List<String> dates = new ArrayList<>();
        LocalDate currentDate = start;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        while (!currentDate.isAfter(end)) {
            dates.add(currentDate.format(formatter));
            currentDate = currentDate.plusDays(1); // 移动到下一天
        }
        return dates;
    }

    private List<TongLianWithdrawDTO> getSettrxList(String dateStr) throws Exception{
        List<FinanceCollectionConfigDO> financeCollectionConfigList = financeCollectionConfigMapper.selectList();
        List<TongLianWithdrawDTO> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(financeCollectionConfigList)){
            return result;
        }
        financeCollectionConfigList = financeCollectionConfigList.stream().filter(c -> PayChannelTypeEnum.TongLian.getCode().equals(c.getPayChannelType())).collect(Collectors.toList());
        List<FinanceCollectionConfigDO> tonglianConfig = financeCollectionConfigList.stream()
                .filter(c -> PayChannelTypeEnum.TongLian.getCode().equals(c.getPayChannelType()))
                .collect(Collectors.toMap(FinanceCollectionConfigDO::getCusId, c -> c, (existing, replacement) -> existing))
                .values()
                .stream()
                .collect(Collectors.toList());
        for (FinanceCollectionConfigDO financeCollectionConfig : tonglianConfig) {
            List<TongLianWithdrawDTO> setttrxFromTongLian = getSetttrxFromTongLian(financeCollectionConfig,dateStr);
            if (CollectionUtils.isNotEmpty(setttrxFromTongLian)){
                result.addAll(setttrxFromTongLian);
            }
        }
        return result;
    }

    private List<TongLianWithdrawDTO> getSetttrxFromTongLian(FinanceCollectionConfigDO financeCollectionConfig, String dateStr) throws Exception{
        if (Objects.isNull(financeCollectionConfig)){
            return null;
        }
        HttpConnectionUtil http = new HttpConnectionUtil("https://vsp.allinpay.com/cusapi/trxfile/setttrx");
        http.init();
        TreeMap<String,String> params = new TreeMap<String,String>();
        params.put("cusid", financeCollectionConfig.getCusId());
        params.put("appid", financeCollectionConfig.getAppId());
        params.put("settdate", dateStr);
        params.put("signtype", "SM2");
        params.put("randomstr",System.currentTimeMillis()+"");
        String appkey = financeCollectionConfig.getCusPrivateKey();
        params.put("sign", SybUtil.unionSign(params,appkey,"SM2"));
        byte[] bys = http.postParams(params, true);
        String result = new String(bys,"UTF-8");
        http.destory();
        log.info("通联返回查询结果：{}", result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        List<TongLianWithdrawDTO> trxlist = JSONArray.parseArray(jsonObject.getString("trxlist"), TongLianWithdrawDTO.class);
        if (CollectionUtils.isNotEmpty(trxlist)){
            List<PayMerchantDO> merchantByAppartmentId = merchantService.getMerchantListByApartment(financeCollectionConfig.getApartmentId());
            PayMerchantDO merchantDO = null;
            if (CollectionUtils.isNotEmpty(merchantByAppartmentId)){
                merchantDO = merchantByAppartmentId.get(0);
            }
            PayMerchantDO finalmerchantDO = merchantDO;
            trxlist.stream().forEach(t -> {
                t.setApartmentId(financeCollectionConfig.getApartmentId());
                if (Objects.nonNull(finalmerchantDO)){
                    t.setAccountId(finalmerchantDO.getId());
                    t.setThirdId(finalmerchantDO.getThirdId());
                }
            });
            return trxlist.stream().filter(t -> StringUtils.isNotBlank(t.getAcctname())).collect(Collectors.toList());
        }
        return trxlist;
    }


}
